package lambda;

import lombok.Data;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;

/**
 * @author： zhangnan
 * @date： 2025/5/20 19:24
 * @description： StreamAPI 测试类
 * @modifiedBy：
 * @version: 1.0
 */
public class TestStreamAPI {

    /**
     * Stream Pipeline；流管道、流水线
     * Intermediate Operations：中间操作
     * Terminal Operation：终止操作
     * <p>
     * Stream所有数据和操作被组合成流管道
     * <p>
     * 流管道组成：
     * 一个数据源(可以是一个数组、集合、生成器函数、I/O管道)
     * 零或多个中间操作(将一个流变形成另一个流)
     * 一个终止曹组(产生最终结果)
     * <p>
     * 流的特性：
     * 流是惰性的(懒加载)，只有在 启动最终操作 时 才会 对数据源进行 计算(执行)，而且只在需要时 才会消耗源元素
     * 如果没有 最终操作 是不会被执行也就不会占用系统的任何资源
     */
    public static void main(String[] args) {
        Stream.of(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
                .filter(ele -> {
                    System.out.println("正在filter： " + ele);
                    return ele % 2 == 0;
                })   // 中间操作
                .max(Integer::compareTo)
                .ifPresent(System.out::println); // terminal operation 终止操作


        /**
         * 流的三大部分：
         *  1. 数据流   2. N个中间操作   3. 一个终止操作
         *
         * 问题1： 流是并发还是不并发
         *  默认不并发，也可以并发(调用中间操作.parallel()方法)；
         *  注意：
         *      开启并发后需要自行解决多线程安全问题；
         *      流的所有操作都是无状态的；数据状态仅在此函数内有效，不溢出至函数外
         *
         * 问题2： 流和for有啥区别？
         *  流也是用for循环挨个处理
         */
        // 测试并发示例
        System.out.println("主线程： " + Thread.currentThread());
        Stream.of(1, 2, 3, 4, 5)
                .parallel() // 中间操作  开启并发流，默认不开启
                .filter(i -> {
                    System.out.println("filter线程： " + Thread.currentThread());
                    System.out.println("正在filter： " + i);
                    return i > 2;
                }) // intermediate operation
                .count(); // terminal operation

        System.out.println("===================");
        List<Persons> list = new ArrayList<>();
        list.add(new Persons("zhang san", "男", 18));
        list.add(new Persons("li si", "女", 22));
        list.add(new Persons("wang wu", "女", 25));
        list.add(new Persons("zhao liu", "男", 28));
        list.add(new Persons("tian qi", "女", 32));
        list.add(new Persons("tian qi", "男", 35));

        /**
         * 第一部分：创建数据流
         *  of、builder、empty、ofNullable、generate、concat、集合(list、set...).stream
         */
//        list.stream();
//        Stream.of(new lambda.Persons("zhangsan", "男", 18), new lambda.Persons("lisi", "女", 22));
//        Stream.generate(() -> {
//            List<Person> list1 = new ArrayList<>();
//            list1.add(new Person("zhangsan","男",18));
//            list1.add(new Person("lisi","女",22));
//            list1.add(new Person("wangwu","女",25));
//            list1.add(new Person("zhaoliu","男",28));
//            list1.add(new Person("tianqi","女",32));
//            return list;
//        });
//        Stream.generate(() -> list);
//        Stream<Object> build = Stream.builder().add(new lambda.Persons("zhangsan", "男", 18)).add(new lambda.Persons("lisi", "女", 22)).build();
//        build.forEach(System.out::println);
//        Stream<String> a = Stream.of("a", "b", "c");
//        Stream<Integer> num = Stream.of(1, 2, 3);
//        Stream.concat(a,num).forEach(System.out::print);
//        Stream<Object> empty = Stream.empty();

        /**
         * 第二部分：中间操作(intermediate operation)
         *
         *
         *
         *  filter(无条件遍历流中的每一元素，然后判断其是否符合条件)：过滤，挑出我们用的元素
         *  takeWhile(当满足条件，拿到这个元素进行后续处理，不满足直接结束流操作)
         *
         *  map：映射，一一映射，如 a 变 b
         *  map、mapToInt、mapToLong、mapToDouble、
         *
         *  flatMap：打散、散列，一对多映射
         *  flatMap、flatMapToInt、flatMapToLong、flatMapToDouble、
         *  mapMulti、mapMultiToInt、mapMultiToLong、mapMultiToDouble、
         *  parallel、unordered、onClose、sequential
         *  distinct(去重)、sorted(排序)、peek(上一步操作处理完成后的数据为入参，一般使用其查看或检查处理后元素)、limit、skip、takeWhile(当条件成立后  )、dropWhile
         */
        // 拿到集合流其实就是拿到集合的深拷贝的值，流的所有操作都是流的元素引用
        // 流里边的每一元素都完整走一个流水线，然后才轮到下一元素；
        // 第一个元素流经所有管道处理后，下一个元素才能继续执行完整管道流程
        // 声明式：基于事件机制的回调
        // stream如果最后没有
        list.stream()
                .filter(item -> item.getAge() > 20)
                .map(Persons::getName)
//                .peek(item -> System.out.println(item.getClass()))
                .distinct()
                .flatMap(name -> {
                    String[] s = name.split(" ");
                    return Arrays.stream(s).distinct();
                })
                .skip(2)
                .sorted(String::compareTo)
                .forEach(System.out::println);
    }

}

@Data
class Persons {

    public Persons (){}

    public Persons (String name,String gender,int age){
        this.name = name;
        this.gender = gender;
        this.age = age;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    private String name;
    private String gender;
    private int age;
}
